using System.Text.Json.Serialization;

namespace LightCAD.Core.Elements
{
    public class Circle : Element
    {
        [JsonInclude,JsonPropertyName("C")]
        [JsonConverter(typeof(Vector2dConverter))]
        public Vector2d Center;
        [JsonInclude, JsonPropertyName("R")]
        [JsonConverter(typeof(DoubleConverter))]
        public double Radius;
        public Circle()
        {
            this.Type = ElementType.Circle;
        }
        public Circle(Vector2d center, double radius) : this()
        {
            this.Center = center;
            this.Radius = radius;
        }
        public Circle(double centerX, double centerY, double radius) : this()
        {
            this.Center.X = centerX;
            this.Center.Y = centerY;
            this.Radius = radius;
        }

        public override Element Clone()
        {
            var clone = new Circle();
            clone.Copy(this);
            clone.Initilize(this.Document);
            return clone;
        }

        public override void Copy(Element src)
        {
            base.Copy(src);
            var circle = ((Circle)src);
            this.Center = circle.Center;
            this.Radius = circle.Radius;
        }

        public void Set(Vector2d? center=null, double? radius=null, bool fireChangedEvent = true)
        {
            //PropertySetter:Center,Radius            
            if (!fireChangedEvent)
            {
                if (center != null) this.Center = center.Value;
                if (radius != null) this.Radius = radius.Value;
            }
            else
            {
                bool chg_center = (center != null && center != this.Center);
                if (chg_center)
                {
                    PropertyChangedBefore(nameof(Center), this.Center,center);
                    var oldValue = this.Center;
                    this.Center = center.Value;
                    PropertyChangedAfter(nameof(Center), oldValue, this.Center);
                }
                bool chg_radius = (radius != null && radius != this.Radius);
                if (chg_radius)
                {
                    PropertyChangedBefore(nameof(Radius), this.Radius,radius);
                    var oldValue = this.Radius;
                    this.Radius = radius.Value;
                    PropertyChangedAfter(nameof(Radius), oldValue, this.Radius);
                }
            }
        }



        public override Box2d GetBoundingBox()
        {
            return new Box2d(new Vector2d(this.Center.X - this.Radius, this.Center.Y - this.Radius),
                new Vector2d(this.Center.X + this.Radius, this.Center.Y + this.Radius));
        }
        public override bool IntersectWithBox(Box2d testBox)
        {
            var thisBox = this.BoundingBox;
            if (!thisBox.IntersectWith(testBox))
            {
                return false;
            }
           

            double bdLeft = testBox.Location.X;
            double bdRight = testBox.Location.X + testBox.Width;
            double bdTop = testBox.Location.Y + testBox.Height;
            double bdBottom = testBox.Location.Y;

            Vector2d nearestPntOnBound = new Vector2d(
               Math.Max(bdLeft, Math.Min(Center.X, bdRight)),
               Math.Max(bdBottom, Math.Min(Center.Y, bdTop)));

            if (Vector2d.Distance(nearestPntOnBound, Center) <= this.Radius)
            {

                return Vector2d.Distance(new Vector2d(bdLeft, bdTop), Center) >= this.Radius
                    || Vector2d.Distance(new Vector2d(bdLeft, bdBottom), Center) >= this.Radius
                    || Vector2d.Distance(new Vector2d(bdRight, bdTop), Center) >= this.Radius
                    || Vector2d.Distance(new Vector2d(bdRight, bdBottom), Center) >= this.Radius;
            }
            else
            {
                return false;
            }

        }


        public override bool IncludeByBox(Box2d testBox)
        {
            var thisBox = this.BoundingBox;
            if (!thisBox.IntersectWith(testBox))
            {
                return false;
            }
            return testBox.Contains(thisBox);
            
        }

        public override void Translate(double dx, double dy)
        {
            var tc = new Vector2d(this.Center.X + dx, this.Center.Y + dy);
            Set(center: tc);
            ResetBoundingBox();
        }
    }

}